Developed by:
Aditya Arcot, Devin Singh, Yi Wang
The goal of our project was to design a Workstation Monitoring embedded system that determines if users are present at their workstations and registers relevant data regarding users. Such data includes their Names, IDs, number of accesses and amount of time spent at each workstation. The Workstation status should be remotely accessible to all users by means of a website.
The Workstation Monitoring system features a GUI designed on Pygame and shown on the PiTFT screen that describes if a workstation is available, and if not, the approximate amount of time remaining for a particular workstation to become available. A user registers to use a workstation by scanning their associated RFID tag. The workstation will then become unavailable on the User Interface screen, and a PI cam will begin to periodically monitor if the user is still at the workstation. If the camera detects that a user is no longer present at a workstation, the workstation will become available. The workstation will also become available when the time remaining for workstation use becomes zero. If multiple users have registered for multiple workstations, the camera will periodically rotate via a camera servo motor to continuously monitor the multiple workstations that are in use. User data such as the number of individual workstation accesses and the amount of time a user spends at a workstation is logged to a database. The workstation availability and approximate time remaining is also logged to the database. This database is then accessed from a webpage hosted on an Apache web server located on the Raspberry Pi, allowing users to view workstation status and user information remotely. Administrators can also use the website to directly modify a user’s name.
A flowchart describing the Workstation Monitoring system operation is shown below:
The following diagram shows the different components of the system:
A user interface is designed to display the status of two stations on a PiTFT. When a user is logged in to a station, the PiTFT would display the user name and the remaining time that the user can use the workstation. The name of the user can be modified on the database through a web page. These working principles are explained in detail in the ‘Database and Website’ section. When no one is logged in to a station, the PiTFT would display this station as available. The first user that logged in would be assigned to station 1. If another RFID tag is detected, the user would be assigned to whichever station that is available.
The PN532 breakout board can be communicated with via SPI, I2C and UART. We decided to use UART to communicate with the board, as it was the most well documented and contained the clearest instructions to configure. The transmit, receive, VCC and ground pins of the PI were necessary to establish serial communication with the RFID reader. The PN532 board must be set-up to accept UART communication by setting both the SEL0 and SEL1 pins located on the board to their OFF positions. The SEL0 and SEL1 pin locations are shown below:
Using the libnfc library, we were able to communicate with the PN532 breakout board through terminal commands on the Raspberry Pi. Using this method, we could simply send a command to the terminal that read from the breakout board for 36 seconds. After 36 seconds, if an RFID tag was not detected, the reading process would timeout. If a tag is present, the process would display the ID associated with the particular tag in the terminal window. Initially, we intended on using system commands from Python to scan for RFID tags and return what was scanned, however, the RFID scanning process through the terminal was blocking and proved difficult to accurately read responses from. Instead, we decided to install the Adafruit Circuit Python library for PN532 UART connection and directly access the RFID reader from our Python code. Doing this proved much easier and made the RFID reader better integrated within our code.
Apart from using RFID to register the user that wishes to log in to a workstation, we also enhanced the security of the system by adding person detection. If a user is logged in to a particular workstation with an RFID card and is not present in the workstation for a predefined amount of time, the user would be evicted. Person detection is achieved by using the OpenCV library in our project. The code we used as a reference and is linked in our references sections of this page. The code from this webpage can detect humans along with animals and many other objects. Since only human recognition is needed in this project, the person detection process would set a signal ‘person_present.value’ to high only when a person is detected. The camera constantly monitors both workstations through the person detection process and determines if a person is present at each workstation.
To monitor both workstations with one camera, we used a servo motor as the camera gimbal. The RPi camera should be connected to the Raspberry Pi CSI port by a cable (as shown in the figure below). The RPi camera is attached to a servo motor, and the steering arm of the servo motor is fixed on a box in the front of both workstations. Hardware PWM is used for the servo motor control instead of software PWM to avoid servo jitter, and using hardware PWM can also save the process time. Each time before using the hardware PWM, we need to use ‘sudo pigpiod’ which can launch the ‘pigpio’ library as a daemon. On the Raspberry Pi, only GPIO Pins 12, 13, 18, and 19 can be used for hardware PWM, and GPIO 12 is used as the PWM input in this project. The power supply to the servo motor (the red wire) should be connected to the 5V output on the Raspberry Pi. And the rotation angle of the servo can be controlled by changing the duty cycle of the PWM signal.
If both workstations are logged in, the servo would rotate and monitor both workstations. For example, the servo is default to monitor workstation 1 on the left first. The Raspberry Pi would run the person detection process to determine if a person is present at the workstation 1. If a person is present, then the servo would rotate and monitor workstation 2. If a person is not present, the servo would run the person detection process another few times before it evicts the user, automatically update the station as being available, and rotate to workstation 2. Once the servo rotates to workstation 2, the Raspberry Pi would again run the person detection process and repeat the aforementioned steps. If only one user is logged in to the workstations, the camera would rotate and only monitor the workstation that is being used.
Workstation status information such as workstation availability and the remaining time a user has to use a particular workstation should be updated and remain accurate, regardless if camera detection is occurring or not. Recall that when detecting if users are present, the camera would first rotate to the appropriate workstation, and then utilize our OpenCV recognition algorithm to determine if a person is present in the camera frame or not. Taking the picture and analyzing via the neural network that was designed was a blocking process and took time. This meant that when checking if a user was present, the timer that was displayed on our PiTFT, would be paused. To fix this, we utilized the multiprocessing library to create two independent processes that operated in parallel. The action of rotating the camera and checking the captured camera image for people was in its own process, while updating the PiTFT screen and the database was kept in a second process. There were variables for each workstation that were sent from the camera check process to the program display process, indicating whether a user was detected or not. If a user was not detected, the availability of the workstation was set to available. Note that the camera checked featured mechanisms that allowed for multiple checks before concluding that a user was no longer present. As previously explained, this was done to ensure a user had actually left the workstation, and did not leave the workstation temporarily.
The database was created using MariaDB, an open-source database management system. The database was hosted on the Raspberry Pi, and supported two way communication with our Python code. MariaDB was installed using apt-get, and a new ‘default’ user was set up having its own credentials, with root permissions to edit database contents. The database consisted of two tables that contained user information and workstation status respectively.
The first table contained user information in relation to the workstations, such as the number of times a user has accessed a particular workstation and the amount of time a user has spent on each. This is done to exemplify that information can be stored regarding user activity on each workstation. The data stored in this table can be incremented using functions that we made in Python, which utilized the mysql-connector library to communicate with the database.
The second table summarizes information displayed on the PiTFT screen, including the workstation status and the remaining time a user has on a workstation that is in use. Similar to the previous table, Python functions were defined that allowed us to modify the contents of the table in real-time.
The contents of the table were able to be viewed via a series of webpages we created that were hosted on an Apache 2 server hosted on the Raspberry Pi. The webpages were designed using PHP and mysql_connect, allowing us to communicate with the database that was being written to by the PI. There were four web pages designed for our Workstation monitoring system. The first webpage communicated with the second data table located on the database, which contained workstation occupancy status, and the remaining time a user has on a particular workstation. This would allow users to know Workstation status remotely, without attending the room where the workstations are located to determine if one could be used. The second webpage summarized the contents of the first table stored in our database, which contained user information regarding the number of accesses and amount of time spent on each workstation. Similar to the first webpage, the second webpage was updated based on the contents of the table it was associated with. This again allowed users to remotely access and view the contents stored in our database. Two more webpages were developed that allowed the administrator to rename users and to remove users if necessary. Renaming users is especially helpful when a new individual is registered within our workstation monitoring system. Recall that in this case, the workstation monitoring system will assign the new user a username. The administrator can then be requested to modify the user’s assigned name to whatever they wish.
Issues were encountered with communicating to the database via PHP. The commands that were sent to the database required special formatting that was not immediately clear. After experimentation, we were able to successfully determine the formatting required to write and read from the database via our web pages.
Altogether, the database was communicated with the Raspberry Pi and with the web pages we developed simultaneously. This aspect of the project also makes it easy to add more workstation monitoring systems to our network. This is because other workstation monitoring systems will have access to all the data stored in the database.
Our system was designed to monitor two workstations. For this reason, we first tested the monitoring capabilities of individual workstations, then we tested the monitoring capabilities when both workstations were occupied. When turning on the Raspberry Pi, a bash script was set to run name start_project.sh, which first reinitialized the pigpiod library for hardware PWM usage, and then started our shutdown script in the background, and finally started our main Python code. The workstations initially begin as available.
When an RFID tag was scanned, the first workstation will immediately be assigned the user's name retrieved from the database.
The camera gimbal will point the camera in the workstation 1 direction all times in this situation, as only workstation one is in use. When blocking the camera or moving out of its frame, the station would automatically update to being available after a few camera checks. We utilized multiple camera checks to ensure that a user is actually no longer present and that they did not temporarily leave the frame. Testing the second workstation alone also yielded similar results. In this case, if only workstation two is occupied, the camera would continuously point at workstation 2. By blocking the camera or leaving the camera frame, the station would also eventually become available.
We also checked if the database updated when a user scans into a workstation and when they leave the workstation. This was done using the webpage we designed.
When each workstation was accessed, we could see that the database would accurately increment the particular workstation access count for each user. Furthermore, when a station becomes available after a user has either left or their workstation time has reached 0, we could also see the overall workstation time for the user update with the amount of time they spent at the workstation.
When single or multiple workstations were in use, both the PiTFT screen and our website would update the workstation status to reflect that a workstation was no longer available.
If both workstations were occupied, the camera gimbal successfully turned periodically to monitor both workstations. It was accurately able to differentiate between when a user was missing from the first workstation and the second workstation, and consistently updated the availability status of workstations when a user was missing from either. It also successfully updated the database with the correct number of access for both users and the correct amount of time spent on a particular workstation when a user leaves their workstation or if their station time ran out.
Finally, when initiating a new user into the system, our workstation successfully assigned them a username based on the number of users present in the system.
Usernames were also able to be edited using the Edit Username webpage, and users could also be removed from our database using the remove user webpage.
Our team successfully implemented and exceeded the requirements for our Workstation Monitoring system that were decided during project week 1. Originally, we intended to build a Workstation monitoring system that simply monitored if users were present via a stable camera and modified workstation availability status based on when an RFID tag was scanned and if a user was in the camera frame. We further expanded our project by introducing a moving camera that could periodically monitor multiple workstations at a time, and by introducing a central database that could be communicated with through our Python code and through a website of our own design, that stored relevant user and workstation information. The Workstation Monitoring system successfully monitored two workstations at a time, and accurately determined if a user was present for both stations using OpenCV person recognition and the camera gimbal. Furthermore, the system successfully communicated with our central database and logged relevant user and workstation information. Finally, our website allowed users to view relevant workstation and user information remotely, and allowed administrators to remove users and also modify their usernames.
When developing our Workstation monitoring system, the main issue we had was with parallelizing camera checking, camera rotation and updating the PiTFT screen and database at the same time. Initially, our camera would rotate on set periods defined by the main python process that updated the PiTFT screen and database information. The camera checking was simply done in parallel with this rotation and updating of the screen and database. This caused issues with synchronizing between camera checks and updating workstation availability. For example, Workstation 1 would be detected as having no user present, however, the camera would rotate and then Workstation 2 would be marked as available instead of Workstation 1. To fix this problem, we synchronized camera rotation with taking pictures and feeding them to our OpenCV code. By doing this, we avoided updating the incorrect workstation, and ensured that workstation checking and camera rotation were completely synchronized. This was the largest issue faced, and allowing for camera checks to happen completely independently of camera rotations would definitely not have allowed our system to meet the requirements we established for our system.
By solving this issue, we could definitely conclude that our Workstation Monitoring system accurately determined when a workstation was in use by a user and updated our database that could be accessed remotely, allowing others to view whether workstations were available remotely. Our workstation monitoring system also updated our database with information regarding individual user usage for each workstation, and also allowed administrators to remove users if necessary, and modify user names.
Aditya was responsible for the PyGame display and getting the individual components such as the RFID reader, camera Gimbal and image identification to work together and meet the requirements of our embedded system. Devin was responsible for creating the web pages that communicated with the database, and writing initial Python code that communicated with the database from the PI, making integration of the database with our main code smoother.Yi was responsible for setting up all hardware, including the RFID reader, camera module and the camera gimbal servo motor so that it could be easily integrable with the main python program.
as3745@cornell.edu
Designed PyGame Display, worked on synchronizing camera rotation with image detection, and Python to database communication.
ds2392@cornell.edu
Designed webpages and worked on database/web server set-up, and communication between webpages and python.
yw2586@cornell.edu
Set up hardware including RFID, camera identifcation and servo motor control signals.
Database and Web Page References and Tutorials:
MariaDB Set-up TutorialOpenCV Person Recognition, Training Data Download and setup instructions:
Object and Animal RecognitionRFID Setup:
Previous RFID ProjectHardware PWM library Setup:
Hardware PWM
// god_version.py (The main program)
# Workstation Monitoring System for the final project of ECE 5725
# Written by Devin Singh (ds2392), Aditya Arcot (as3745), Yi Wang (yw2586)
import RPi.GPIO as GPIO
import serial
import time
import os
import pygame
from pygame.locals import *
from time import sleep
import pigpio # for using hardware PWM
import cv2 # for object detection
from adafruit_pn532.uart import PN532_UART # for RFID
import os
import mysql.connector as database
import multiprocessing
username = os.environ.get("username")
password = os.environ.get("password")
#Connect to mariadb
connection = database.connect(user='default', password='password',
host="localhost", database="final_project")
#Cursor to move through rows of 'users' table
cursor = connection.cursor()
os.putenv('SDL_VIDEODRIVER','fbcon') #Display on PiTFT
os.putenv('SDL_FBDEV','/dev/fb0')
os.putenv('SDL_MOUSEDRV','TSLIB') #Track mouse clicks on PiTFT
os.putenv('SDL_MOUSEDEV','/dev/input/touchscreen')
pygame.init()
pygame.mouse.set_visible(False)
# character font displayed on piTFT
WHITE = 255, 255, 255
BLACK = 0,0,0
GREEN = 0, 255, 0
RED = 255, 0, 0
screen=pygame.display.set_mode((320, 240))
#uart setup
uart = serial.Serial("/dev/ttyS0", baudrate=115200, timeout=1)
pn532 = PN532_UART(uart, debug=False)
ic, ver, rev, support = pn532.firmware_version
#Configure PN532
pn532.SAM_configuration()
#Wrokstation user workstation : user_id
workstation_user = { 1:1, 2:1}
user_id = {0: "Available", 1: "Devin", 2:"Yi", 3: "Adi"}
rfid_tags = { 1:"Available", 0:"-"}
my_font = pygame.font.Font(None, 25)
my_buttons = {(160, 40):'Workstation Activity', (60, 100):'Station 1:', (60, 140):'Station 2'}
workstation_status = {(160, 100): '%s'%(rfid_tags[workstation_user[1]]), (160, 140): '%s'%(rfid_tags[workstation_user[2]])} #store the RFID tags of each user
workstation_time = {1:0, 2:0}
my_times = { (240, 100):'%d'%(workstation_time[1]), (240, 140):'%d'%(workstation_time[2])} # remaining login time for each user
screen.fill(BLACK)
my_buttons_rect= {}
for text_pos, my_text in my_buttons.items():
text_surface = my_font.render(my_text, True, WHITE)
rect = text_surface.get_rect(center = text_pos)
screen.blit(text_surface, rect)
my_buttons_rect[my_text] = rect
for text_pos, my_text in workstation_status.items():
if (my_text == "Available"):
text_surface = my_font.render(my_text, True, GREEN)
else:
text_surface = my_font.render(my_text, True, RED)
rect = text_surface.get_rect(center = text_pos)
screen.blit(text_surface, rect)
pygame.display.flip()
#define switches to be used
SW1 = 17
SW2 = 22
SW3 = 23
SW4 = 27
LED = 26
GPIO.setmode(GPIO.BCM)
GPIO.setup(SW1, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(SW2, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(SW3, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(SW4, GPIO.IN, pull_up_down = GPIO.PUD_UP)
GPIO.setup(26,GPIO.OUT)
# this function updates the workstation occupancy and remaining time to the database
def update_ws_table(ws, status_, remaining_time):
try:
statement = "UPDATE ws_occupancy SET status_ = %s, remaining_time = %s WHERE workstation = %s"
data = (status_, remaining_time, ws)
cursor.execute(statement, data)
connection.commit()
except database.Error as e:
print("Error entering database information from update_ws_table: {e}")
def increment_access_count(first_name, WS):
try:
if (WS == 1):
statement = "UPDATE users SET WS1_noof_access = WS1_noof_access + 1 WHERE first_name = %s"
elif(WS == 2):
statement = "UPDATE users SET WS2_noof_access = WS2_noof_access + 1 WHERE first_name = %s"
data = (first_name,)
cursor.execute(statement, data)
connection.commit()
print("Successfully incremented Workstation %s access count" % WS)
except database.Error as e:
print("Error entering database information from increment access count: {e}")
def check_name(rfid):
try:
query = "SELECT COUNT(*) FROM users WHERE rfid = %s"
cursor.execute(query, (rfid,))
result = cursor.fetchone()
if result[0] == 0:
return False
else:
return True
except Exception as e:
print(f"Error: {e}")
def check_num():
try:
statement = "SELECT COUNT(*) FROM users"
cursor.execute(statement)
result = cursor.fetchone()
return result
except Exception as e:
print(f"Error: {e}")
# update the user and the corresponding RFID to the database
def add(first_name,rfid):
try:
statement = "INSERT INTO users (first_name,rfid) VALUES (%s, %s)"
data = (first_name, rfid)
cursor.execute(statement, data)
connection.commit()
print("Successfully added user to database")
except database.Error as e:
print("Error entering database information: %s" % e)
# return the user name to the corresponding RFID tag and update to the database
def get_data(rfid):
try:
statement = "SELECT first_name, rfid FROM users WHERE rfid=%s"
data = (rfid,)
cursor.execute(statement, data)
for (first_name, rfid) in cursor:
print(f"Successfully retrieved {first_name}, {rfid}")
return first_name
except database.Error as e:
print(f"Error retrieving entry from database: {e}")
return False
# update the userer name, the station that he is using and the remainging time to the database
def modify_session_time(first_name, WS, session_time):
try:
if (WS == 1):
statement = "UPDATE users SET WS1_total_time = WS1_total_time + %s WHERE first_name = %s"
elif(WS == 2):
statement = "UPDATE users SET WS2_total_time = WS2_total_time + %s WHERE first_name = %s"
data = (session_time, first_name)
cursor.execute(statement, data)
connection.commit()
print("Successfully updated WS %d time" % WS)
except database.Error as e:
print("Error entering database information: {e}")
# quit this python program if called
def quit_callback(channel):
global code_run
print("*************************Code exiting************")
code_run.value= 0
time_limit = 300
start_time = time.time()
code_run = True
#Open CV Functions
#This is to pull the information about what each object is called
classNames = []
classFile = "/home/pi/Desktop/Object_Detection_Files/coco.names"
with open(classFile,"rt") as f:
classNames = f.read().rstrip("\n").split("\n")
#This is to pull the information about what each object should look like
configPath = "/home/pi/Desktop/Object_Detection_Files/ssd_mobilenet_v3_large_coco_2020_01_14.pbtxt"
weightsPath = "/home/pi/Desktop/Object_Detection_Files/frozen_inference_graph.pb"
#This is some set up values to get good results
net = cv2.dnn_DetectionModel(weightsPath,configPath)
net.setInputSize(320,320)
net.setInputScale(1.0/ 127.5)
net.setInputMean((127.5, 127.5, 127.5))
net.setInputSwapRB(True)
#This is to set up what the drawn box size/colour is and the font/size/colour of the name tag and confidence label
def getObjects(img, thres, nms, draw=True, objects=[]):
classIds, confs, bbox = net.detect(img,confThreshold=thres,nmsThreshold=nms)
#Below has been commented out, if you want to print each sighting of an object to the console you can uncomment below
#print(classIds,bbox)
if len(objects) == 0: objects = classNames
objectInfo =[]
if len(classIds) != 0:
for classId, confidence,box in zip(classIds.flatten(),confs.flatten(),bbox):
className = classNames[classId - 1]
if className in objects:
objectInfo.append([box,className])
if (draw):
cv2.rectangle(img,box,color=(0,255,0),thickness=2)
cv2.putText(img,classNames[classId-1].upper(),(box[0]+10,box[1]+30),
cv2.FONT_HERSHEY_COMPLEX,1,(0,255,0),2)
cv2.putText(img,str(round(confidence*100,2)),(box[0]+200,box[1]+30),
cv2.FONT_HERSHEY_COMPLEX,1,(0,255,0),2)
pass
return img,objectInfo
# rotate the servo motor (the camera is attached to)
def rotate_cam(pos):
if(pos == 0): # if the servo is pointing towards workstation 1 (on the left)
print("camera turn right")
pi_hw.hardware_PWM(12, 50, 90000)
return 1
elif(pos == 1): # if the servo is pointing towards workstation 2 (on the right)
print("camera turn left")
pi_hw.hardware_PWM(12, 50, 45000)
return 0
#Camera Call function
def check_camera(person_present1, person_present2, check, code_run):
GPIO.add_event_detect(SW1, GPIO.FALLING, callback=quit_callback, bouncetime=300)
pi_hw.hardware_PWM(12, 50, 45000)
timeout1=0
timeout2=0
pos = 0 #position of camera
print("process started")
print(code_run.value)
while(code_run.value==1):
if(check.value == 0): # only work station 1 is being logged in or neither workstations are being used
if(pos == 1):
pos = rotate_cam(pos)
time.sleep(5)
print("Checking camera 1")
os.system('raspistill -w 640 -h 480 -t 2000 -n -o /home/pi/Desktop/image.jpg')
img = cv2.imread("/home/pi/Desktop/image.jpg")
result, objectInfo = getObjects(img,0.60,1, objects = ['person'])
print("Result is")
print(objectInfo)
if (not objectInfo): # if a person if not detected in a camera fram
if(timeout1==1):
person_present1.value = 0 # a person is not present at the workstation 1
timeout1 = 0
time.sleep(3)
else: # wait for 3 seconds to take another picture
person_present1.value = 1 # a person is not present at the workstation 1
timeout1 = 1
time.sleep(3)
print("time")
else:
person_present1.value = 1 # a person is not present at the workstation 1
timeout1 = 0
if(check.value == 1): # only the workstation 2 is being logged in
if(pos == 0):
pos = rotate_cam(pos)
time.sleep(5)
print("Checking camera 2")
os.system('raspistill -w 640 -h 480 -t 2000 -n -o /home/pi/Desktop/image.jpg')
img = cv2.imread("/home/pi/Desktop/image.jpg")
result, objectInfo = getObjects(img,0.60,1, objects = ['person'])
print("Result is")
print(objectInfo)
if (not objectInfo): # if a person if not detected in a camera fram
if(timeout2==1):
person_present2.value = 0 # a person is not present at the workstation 2
timeout2 = 0
time.sleep(3)
else: # wait for 3 seconds to take another picture
person_present2.value = 1 # a person is present at the workstation 2
timeout2 = 1
time.sleep(3)
else:
person_present2.value = 1 # a person is present at the workstation 2
timeout2 = 0
if(check.value == 2): # both workstations are being used
if(pos == 1):
pos = rotate_cam(pos) # rotate the servo (and camera) to workstation 1 if not already looking at workstation 1
time.sleep(5)
print("Checking camera 1")
os.system('raspistill -w 640 -h 480 -t 2000 -n -o /home/pi/Desktop/image.jpg')
img = cv2.imread("/home/pi/Desktop/image.jpg")
result, objectInfo = getObjects(img,0.60,1, objects = ['person'])
print("Result is")
print(objectInfo)
if (not objectInfo): # if a person if not detected in a camera fram
if(timeout1==1):
person_present1.value = 0 # a person is not present at the workstation 1
timeout1 = 0
time.sleep(3)
else: # wait for 3 seconds to take another picture
person_present1.value = 1 # a person is present at the workstation 1
timeout1 = 1
time.sleep(3)
else:
person_present1.value = 1 # a person is present at the workstation 1
timeout1 = 0
if(pos == 0):
pos = rotate_cam(pos) # rotate the servo (and camera) to workstation 2 if not already looking at workstation 1
time.sleep(5)
print("Checking camera 2")
os.system('raspistill -w 640 -h 480 -t 2000 -n -o /home/pi/Desktop/image.jpg')
img = cv2.imread("/home/pi/Desktop/image.jpg")
result, objectInfo = getObjects(img,0.60,1, objects = ['person'])
print("Result is")
print(objectInfo)
if (not objectInfo): # if a person if not detected in a camera fram
if(timeout2==1):
person_present2.value = 0 # a person is not present at the workstation 2
timeout2 = 0
time.sleep(5)
else: # wait for 5 seconds to take another picture
person_present2.value = 1 # a person is present at the workstation 2
timeout2 = 1
time.sleep(5)
else:
person_present2.value = 1 # a person is present at the workstation 2
timeout2 = 0
cv2.waitKey(1)
# this function returns the RFID scanned data
def rfid_read():
uid = pn532.read_passive_target(timeout=0.5)
if uid is None:
return None
else:
la = [str(i) for i in uid]
tag = ','.join(la)
return tag
pi_hw = pigpio.pi()
#Declare Camera thread
#Main while
username1 = None
def main_program(person_present1, person_present2, check,code_run):
GPIO.add_event_detect(SW1, GPIO.FALLING, callback=quit_callback, bouncetime=300)
st1 = True
st2 = True
username1 = None
username2 = None
time1 = 0
time2 = 0
pi_hw.hardware_PWM(12, 50, 45000) # initialize the servo towards workstation 1
while(code_run.value == 1):
if(workstation_user[1]==1 or workstation_user[2]==1):
temp = rfid_read() # get the RFID tag data
if(temp != None):
tag = temp
print(tag)
if(workstation_user[1]==1): # workstation 1 is logged in
print(check_name(tag))
if(check_name(tag)):
print(get_data(tag))
username1temp = get_data(tag)
else:
name = "User" + str(check_num()[0]+1)
add(name,tag) # update the user and the corresponding RFID to the database
username1temp = name
print(username2)
if(username2 != username1temp): # register the user to station 1 only if the user is not already logged in to station 2
username1 = username1temp
workstation_user[1] = 0
workstation_time[1] = 120 # reinitialize the remaining time for station 1 as 120 seconds
elif(workstation_user[2]==1):
if(check_name(tag)):
username2temp = get_data(tag)
else:
name = "User" + str(check_num()[0]+1)
add(name,tag) # update the user and the corresponding RFID to the database
username2temp = name
if(username1 != username2temp): # register the user to station 2 only if the user is not already logged in to station 1
username2 = username2temp
workstation_user[2] = 0
workstation_time[2] = 120 # reinitialize the remaining time for station 1 as 120 seconds
# neither of the stations are being used
if(workstation_user[1] and workstation_user[2]):
workstation_status = {(160, 100): '%s' % (rfid_tags[1]), (160, 140): '%s' % (rfid_tags[1])}
update_ws_table(1, "Available", workstation_time[1]) #updates the workstation 1 occupancy and remaining time to the database
update_ws_table(2, "Available", workstation_time[2]) #updates the workstation 2 occupancy and remaining time to the database
check.value = 0
# only station 2 is being used
elif(workstation_user[1] and not (workstation_user[2])):
workstation_status = {(160, 100): '%s'%(rfid_tags[1]), (160, 140): '%s'%(username2)}
update_ws_table(1, "Available", workstation_time[1])
update_ws_table(2, username2, workstation_time[2])
check.value = 1
# only station 1 is being used
elif(not workstation_user[1] and (workstation_user[2])):
workstation_status = {(160, 100): '%s'%(username1), (160, 140): '%s'%(rfid_tags[1])}
update_ws_table(1, username1, workstation_time[1])
update_ws_table(2, "Available", workstation_time[2])
check.value = 0
# both stations are being used
else:
workstation_status = {(160, 100): '%s'%(username1), (160, 140): '%s'%(username2)}
update_ws_table(1, username1, workstation_time[1])
update_ws_table(2, username2, workstation_time[2])
check.value = 2
my_times = { (240, 100):'%d'%(workstation_time[1]), (240, 140):'%d'%(workstation_time[2])}
if(workstation_time[1]>0 ): # update the remainging time for workstation1
if(time.time()-time1>1):
workstation_time[1] = workstation_time[1] - 1 # decrease the remaining time by 1 second
time1 = time.time()
if (workstation_time[1] == 116):
increment_access_count(username1, 1)
if(workstation_time[1]<100): # evict the user if a person is not present in the workstation after 20 seconds
if(person_present1.value == 0):
workstation_user[1] = 1
modify_session_time(username1,1,120-workstation_time[1]) # update the userer name, the station that he is using and the remainging time to the database
username1 = None
workstation_time[1] = 0
if(workstation_time[1]==1 and st1):
modify_session_time(username1,1,120)
st1 = False
if(workstation_time[1]==0):
workstation_user[1] = 1
username1 = None
st1 = True
if(workstation_time[2]>0 ): # update the remainging time for workstation2
if(time.time()-time2>1):
workstation_time[2] = workstation_time[2] - 1 # decrease the remaining time by 1 second
time2 = time.time()
if (workstation_time[2] == 116):
increment_access_count(username2, 2)
if(workstation_time[2]<100): # evict the user if a person is not present in the workstation after 20 seconds
if(person_present2.value == 0):
workstation_user[2] = 1
modify_session_time(username2,2,120-workstation_time[2]) # update the userer name, the station that he is using and the remainging time to the database
username2 = None
workstation_time[2] = 0
if(workstation_time[2]==1 and st2):
modify_session_time(username2,2,120)
st2 = False
if(workstation_time[2]==0):
workstation_user[2] = 1
st2 = True
username2 = None
# update the display on the piTFT
for text_pos, my_text in my_buttons.items():
text_surface = my_font.render(my_text, True, WHITE)
rect = text_surface.get_rect(center = text_pos)
screen.blit(text_surface, rect)
my_buttons_rect[my_text] = rect
for text_pos, my_text in workstation_status.items():
if (my_text == "Available"):
text_surface = my_font.render(my_text, True, GREEN)
else:
text_surface = my_font.render(my_text, True, RED)
rect = text_surface.get_rect(center = text_pos)
screen.blit(text_surface, rect)
#my_buttons_rect[my_text] = rect
for text_pos, my_text in my_times.items():
if(my_text != "0"):
text_surface = my_font.render(my_text, True, RED)
rect = text_surface.get_rect(center = text_pos)
screen.blit(text_surface, rect)
my_buttons_rect[my_text] = rect
pygame.display.flip()
screen.fill(BLACK)
time.sleep(1/60)
if __name__ == "__main__":
code_run = multiprocessing.Value('i', 1)
person_present1 = multiprocessing.Value('i', 1)
person_present2 = multiprocessing.Value('i', 1)
check = multiprocessing.Value('i', 0)
process = multiprocessing.Process(target = check_camera, args=(person_present1, person_present2, check, code_run, ))
process1 = multiprocessing.Process(target = main_program, args=(person_present1, person_present2, check, code_run, ))
process.start()
process1.start()
process.join()
process1.join()
//shutdown.py (Background program to shutdown pi on button press)
import RPi.GPIO as GPIO
import time
import os
# Set the GPIO mode and pin
GPIO.setmode(GPIO.BCM)
shutdown_pin = 23 # Change this to the GPIO pin you have connected the button to
# Set up the button as an input with pull-up resistor
GPIO.setup(shutdown_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def shutdown(channel):
print("Button pressed! Shutting down...")
time.sleep(1) # Optional delay to avoid accidental triggers
os.system("sudo killall pigpiod") #To endsure proper working of hardware pwm
os.system("sudo shutdown -h now") #shutdown the pi
# Add event detection for the button press
GPIO.add_event_detect(shutdown_pin, GPIO.FALLING, callback=shutdown, bouncetime=2000)
try:
# Keep the script running
while True:
time.sleep(1)
except KeyboardInterrupt:
# Clean up GPIO on keyboard interrupt
GPIO.cleanup()
//startup_proj.sh(Shell script to run at startup)
sudo killall pigpiod
sudo pigpiod
sudo python /home/pi/project/shutdown.py &
sudo python /home/pi/project/god_version.py
//index.php (Website home page)
<!DOCTYPE html>
<html lang="en">
<head>
<meta chaset="UTF-8">
<meta http-equivx="X-UA-Compatible" content="IE=edge">
<meta http-equiv="refresh" content="5">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Workstation Monitoring System</title>
<h1> Workstation Monitoring System </h1>
<style>
.button {
background-color: #00008b;
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 10px 10px;
cursor: pointer;
}
.button:hover {
background-color: #77C3EC;
color: white;
}
</style>
</head>
<body>
<!-- <button>Default Button</button> -->
<a href="database_summary.php" class="button">User Analytics</a>
</a>
<a href="edit_username.php" class="button">
Edit Username
</a>
<a href="remove_user.php" class="button">
Remove User
</a>
<br>
<hr>
<br>
<h3> Workstation Occupancy List </h3>
<style type="text/css">
table {
border-collaspe: collapse;
width: 50%;
height: 10%;
color: #00008b;
font-family: monospace;
font-size: 25px;
text-align: center;
}
th{
background-color: #00008b;
color: white;
}
th {
text-align: center;
}
tr:nth-child(even) {background-color: #f2f2f2};
</style>
<table>
<tr>
<th>Workstation</th>
<th>Status</th>
<th>Time Remaining</th>
<?php
$servername = "localhost";
$username = "default";
$password = "password";
$databasename = "final_project";
// CREATE CONNECTION
$conn = mysqli_connect($servername,
$username, $password, $databasename);
// GET CONNECTION ERRORS
if (!$conn) {
die("Connection failed: " . mysqli_connect_error());
}
// SQL QUERY
$query = "SELECT workstation, status_,
remaining_time FROM `ws_occupancy`;";
try
{
$conn = new PDO(
"mysql:host=$servername;dbname=$databasename",
$username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $conn->prepare($query);
// EXECUTING THE QUERY
$stmt->execute();
$r = $stmt->setFetchMode(PDO::FETCH_ASSOC);
// FETCHING DATA FROM DATABASE
$result = $stmt->fetchAll();
// OUTPUT DATA OF EACH Row
$WS1_flag = 0;
$WS2_flag = 0;
foreach ($result as $row)
{
if ($row["workstation"] == 1) { //If workstation 1 is being used
if ($row["remaining_time"] == 0) {
echo "<tr><td>". "Workstation 1" . "</td><td> <strong> <font color = #006400>" . $row["status_"] . "</strong></td><td>" . $row["remaining_time"] . "</td><tr>";
}
else {
echo "<tr><td>". "Workstation 1" . "</td><td>" . $row["status_"] . "</td><td>" . $row["remaining_time"] . "</td><tr>";
$WS1_flag = 1;
}
}
if ($row["workstation"] == 2 ) { //If workstation 1 is being used
if ($row["remaining_time"] == 0) {
echo "<tr><td>". "Workstation 2" . "</td><td> <strong> <font color = #006400>" . $row["status_"] . "</strong></td><td>" . $row["remaining_time"] . "</td><tr>";
}
else {
echo "<tr><td>". "Workstation 2" . "</td><td>" . $row["status_"] . "</td><td>" . $row["remaining_time"] . "</td><tr>";
$WS1_flag = 1;
}
}
}
echo "</table>";
} catch(PDOException $e) {
echo "Error: " . $e->getMessage();
}
$conn->close();
echo "<a href=\"database_summary.php\"> <button>Database</button> </a>"
?>
</body>
</html>